﻿/*
 * Cratos Entity
 * Cratos Entity Collection class
 * 
 * Copyright (c) 2011-2012 Draco
 * 
 * This file is part of Cratos.
 * 
 * Cratos is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * Cratos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cratos.  If not, see <http://www.gnu.org/licenses/>.
 * 
 *       .==.        .==.
 *      //'^\\      //^'\\
 *     // ^ ^\(\__/)/^ ^^\\
 *    //^ ^^ ^/6  6\ ^^ ^ \\
 *   //^ ^^ ^/( .. )\^ ^ ^ \\
 *  // ^^ ^/\| V""V|/\^ ^ ^ \\
 * //^^/\/ /  '~~'  \ \/\^ ^ \\
 *  ------------------------------------
 *  HERE BE DRAGONS
 *  
 *  Johan Dercksen - johan@draco.co.za
 */
using System;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;

using Cratos.Tools.General;
using Cratos.Tools.DataObject;

namespace Cratos.Server.Entity
{
	/// <summary>
	/// Cratos Entity Collection class
	/// </summary>
	public class CratosEntityCollection<T> : CratosEntityCollectionBase<T> where T : IDOCratos, new()
	{
		#region Class Constant declarations
		#endregion

		#region Class Event declarations
		#endregion

		#region Class Variable declarations
		private IDOCratos								dataObject;
		private IDOCratosCollection<T>	doCollection;
		#endregion

		#region Class Constructors & Destructors
		/// <summary>
		/// Class Constructor
		/// </summary>
		public CratosEntityCollection() : base() { }
		#endregion

		#region Class Properties
		#endregion

		#region Class Methods
		/// <summary>
		/// Entity Perform Action
		/// </summary>
		/// <returns>A Boolean indicating success of the method</returns>
		public override bool PerformAction(IDOCratosCollection<T> cratosDOCollection)
		{
			// Declare the required variables
			bool returnValue = false;

			try
			{
				// Reset all the relevant values
				this.Errors.Clear();

				// Save the relevant values
				this.dataObject		= (T)cratosDOCollection.DataObject.Clone();
				this.doCollection = cratosDOCollection;

				// Setup the DB Connection Name if required
				if (string.IsNullOrEmpty(this.doCollection.DataObject.DBConnectionName))
				{
					this.doCollection.DataObject.DBConnectionName = DOCratosGlobal.DBConnectionName;
				}

				// Validate the Data Object
				if (cratosDOCollection.Validate())
				{
					// Setup the DB Connection
					if (this.DBConnect(this.IgnoreUnity, this.dataObject.DBConnectionName, this.dataObject.DBActionType))
					{
						  // Handle the relevant List Action
						  switch (cratosDOCollection.CollectionAction)
						  {
						    case DOCratosCollectionAction.Retrieve:
									// Perform the relevant action
									returnValue = this.PerformRetrieve();
									break;

								case DOCratosCollectionAction.Various:
									// Perform the relevant action
									returnValue = this.PerformVarious();
									break;

								default:
									throw new Exception("Cratos Data Object Collection Action not implemented");
							}
					}
				}
			}
			catch (Exception runtimeException)
			{
				// Create and setup a new error
				this.Errors.Add(new CratosError("CratosEntityCollection.PerformAction", CratosLogSeverity.Exception,
																				"Runtime error ocurred", runtimeException));
			}
			finally
			{
			}

			// Return to calling method
			return (returnValue);
		}
		#endregion

		#region Class Support Methods
		private bool PerformRetrieve()
		{
			// Declare the required variables
			bool			returnValue = false;
			IDOCratos newResultDO;

			try
			{
				// Setup the Database Command
				if (!this.DBSetupCollectionCommand<T>(this.doCollection)) { return (returnValue); }

				// Setup the Database Parameters
				this.DBSetupCollectionParameters<T>(this.doCollection);

				// Make sure we have no errors before executing
				if (this.Errors.Count <= 0)
				{
					#region Execute the stored procedure and process results
					// Set the default Action Result
					this.dataObject.DOActionResult = DOCratosActionResult.Error;

					// Handle the relevant output if expected
					if (this.DBActionAttribute.IsExpectOutput)
					{
						#region Action Expects output
						// Execute the Action
						if (this.DBExecuteReader() && this.DBReaderHasRows)
						{
							do 
							{
								// Create and setup the new Data Object
								newResultDO = new T();

								// Populate the Data Object
								this.DBLoadDataFromReader(newResultDO);

								// Add the Data Object to the list
								this.doCollection.Add(newResultDO);
							} while (this.DBReaderRead() && (this.doCollection.Count < this.doCollection.MaxRecords));

							#region Process Embedded Objects
							// Process all the Embedded Object Attributes
							foreach (DOCratosEmbeddedAttribute currentEmbeddedAttribute in this.dataObject.AllDOEmbedded)
							{
								// Process all the Objects in the collection
								foreach (T currentDOObject in this.doCollection)
								{
									// Handle the List section
									if (currentEmbeddedAttribute.IsCollection)
									{
										// Process the Embedded Object
										this.ProcessEmbeddedCollection(DOCratosHelper.GetPropertyValue(this.dataObject, currentEmbeddedAttribute.Property),
																									 currentDOObject, currentEmbeddedAttribute);
									}
									else
									{
										// Process the Embedded Object
										this.ProcessEmbeddedObject((IDOCratos)DOCratosHelper.GetPropertyValue(this.dataObject, currentEmbeddedAttribute.Property),
																							 currentDOObject, currentEmbeddedAttribute);
									}
								}
							}
							#endregion

							// Update the List Action Result
							this.doCollection.CollectionActionResult = DOCratosActionResult.Success;
						}
						#endregion
					}
					else
					{
						#region No Output Expected
						// Execute the Action
						this.DBExecuteNonQuery();

						// Update the Action Result
						this.dataObject.DOActionResult = DOCratosActionResult.Success;
						#endregion
					}
					#endregion
				}
			}
			catch (Exception runtimeException)
			{
				// Create and setup a new error
				this.Errors.Add(new CratosError("CratosEntityCollection.PerformRetrieve", CratosLogSeverity.Exception,
																				"Runtime error ocurred", runtimeException));
			}
			finally
			{
				// Set the successful return value
				returnValue = (this.Errors.Count <= 0);
			}

			// Return to calling method
			return (returnValue);
		}

		private bool PerformVarious()
		{
			// Declare the required variables
			bool returnValue = false;

			try
			{
				// Setup the Database Command
				if (!this.DBSetupCollectionCommand<T>(this.doCollection)) { return (returnValue); }

				// Setup the Database Parameters
				this.DBSetupCollectionParameters<T>(this.doCollection);

				// Make sure we have no errors before executing
				if (this.Errors.Count <= 0)
				{
					// Set the default Action Result
					this.dataObject.DOActionResult = DOCratosActionResult.Error;

					// Process all the items in the collection
					foreach (T currentDO in this.doCollection)
					{
						// Make sure we have an action to perform
						if (currentDO.DOAction != DOCratosAction.None)
						{
							// Perform the required action
							if (!currentDO.PerformAction())
							{
								// Process all the errors
								foreach (CratosError currentError in currentDO.Errors) { this.Errors.Add(currentError); }
							}
						}
					}
				}
			}
			catch (Exception runtimeException)
			{
				// Create and setup a new error
				this.Errors.Add(new CratosError("CratosEntityCollection.PerformVarious", CratosLogSeverity.Exception,
																				"Runtime error ocurred", runtimeException));
			}
			finally
			{
				// Set the successful return value
				returnValue = (this.Errors.Count <= 0);

				// Update the List Action Result
				if (returnValue) { this.doCollection.CollectionActionResult = DOCratosActionResult.Success; }
			}

			// Return to calling method
			return(returnValue);
		}
		#endregion
	}
}
